// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using JetBrains.Annotations; namespace LargoCommon.Music { /// /// Melodic Analyzer. /// [UsedImplicitly] public sealed class MelodicAnalyzer { #region Properties /// /// Gets the melodic model. /// /// /// The melodic model. /// public MelodicModel MelodicModel { get; private set; } /// /// Gets the rhythmic model. /// /// /// The rhythmic model. /// public RhythmicModel RhythmicModel { get; private set; } #endregion #region Public methods - Melodic Analyze /// /// Analyze Musical Lines. /// /// The melodic model. /// The rhythmic model. /// The musical block. public void AnalyzeMusicalLines(MelodicModel melodicModel, RhythmicModel rhythmicModel, MusicalBlock givenBlock) { Contract.Requires(givenBlock != null); //// if (givenBlock == null) { return; } this.MelodicModel = melodicModel; this.RhythmicModel = rhythmicModel; //// Cannot be run as parallel (because of direct addition of motives to entity framework collections?!?) IList melodicItems = this.ExtractMelodicItems(givenBlock); var melodicStreamAnalyzer = new MelodicStreamAnalyzer(melodicItems); var itemGroups = new List(); //// Determine motives as group of items foreach (var musicalTrack in givenBlock.Strip.Lines) { while (true) { var items = melodicStreamAnalyzer.GetNextMotiveItems(musicalTrack.LineIndex); //// .ToList(); if (items == null || !items.Any()) { break; } var itemGroup = new MelodicItemGroup(items, musicalTrack); itemGroups.Add(itemGroup); } } //// Main algorithm to determine motivic classes and their instances this.RhythmicModel.AppendRhythmicMotives(itemGroups); this.MelodicModel.AppendMelodicMotives(itemGroups); } /// /// Extracts the melodic items. /// /// The given block. /// /// Returns object. /// public IList ExtractMelodicItems(MusicalBlock givenBlock) { List items = new List(); //// MusicalTone lastMelodicTone = null; for (int lineIndex = 0; lineIndex < givenBlock.Header.NumberOfLines; lineIndex++) { foreach (var bar in givenBlock.Body.Bars) { var element = bar.Elements[lineIndex]; if (element.Line == null || !element.Status.HasContent) { continue; } //// Rhythmical and melodical structure in bar //// Rhythmical structure in bar RhythmicStructure rstruct = element.Status.RhythmicStructure; if (rstruct == null) { continue; } //// Melodic structure in bar MelodicStructure mstruct = null; var isMelodic = element.Status.IsMelodic; if (isMelodic) { mstruct = element.Status.MelodicStructure; } var musicalTonesInBar = element.Tones; MusicalToneCollection melodicTonesInBar = element.SingleMelodicTones(); var melodicItem = new MelodicItem(bar, element.Line.LineIndex, rstruct, mstruct) { MusicalTones = musicalTonesInBar, MelodicTones = melodicTonesInBar }; items.Add(melodicItem); } } return items; } #endregion } }